package com.AdvancedDemos.Lambda表达式与方法引用;

interface InterA {
    //接口功能是求两个整数最大值并返回
    public abstract int getMax(int num1, int num2);
}

interface InterB {
    //打印字符串
    public abstract void print(String str);
}


interface InterC {
    //获取学生对象
    public abstract Student getStudent();
}

public class MethodReference方法引用 {
    public static void main(String[] args) {
        /*
            方法引用是对lambda表达式的进一步优化
            Lambda:数据->功能
            方法引用:只关注功能,省去了数据,因为数据必定会传给功能
        */


        //场景1:类名::静态方法名
        int max;
        max = useInterA(new InterA() {
            @Override
            public int getMax(int num1, int num2) {
                return Math.max(num1, num2);
            }
        }, 10, 20);//原始匿名内部类形式

        max = useInterA((num1, num2) -> Math.max(num1, num2), 10, 20);//lambda表达式形式

        max = useInterA(Math::max, 10, 20);//方法引用形式

        System.out.println("max = " + max);

        /**
         * 以场景一中匿名内部类中重写InterA类中的getMax函数为例(场景二三类似),简化成Lambda表达式形式甚至进一步简化成方法引用形式,看似丢失了很多信息,实际上一个也没少,看似十分神奇,实际上编译器并没有智能地做任何事,所需的信息早已通过上下文中手动给出.
         *
         * max = useInterA(new InterA() {
         *        @Override
         *        public int getMax(int num1, int num2) {
         *                  return Math.max(num1, num2);
         *             }
         *        }, 10, 20);//原始匿名内部类形式
         *
         *匿名内部类形式中第一个参数是一个实现了InterA接口的实现类的对象,重写唯一抽象函数与创建对象一气呵成,重写函数getMax函数有两个形参int num1和int num2,在函数体内由程序员给出了具体实现,调用了Math类中的max函数,并将num1与num2依次赋给了两个形参,返回max函数运算的结果
         *
         * max = useInterA((num1, num2) -> Math.max(num1, num2), 10, 20);//lambda表达式形式
         *
         * Lambda表达式形式中(num1, num2)表示唯一抽象函数getMax的两个参数列表,->右边是getMax函数体中具体的实现,其中调用了Math类中的max方法,并将num1与num2依次赋给了两个形参,自动返回max函数运算的结果
         *
         * max = useInterA(Math::max, 10, 20);//方法引用形式
         *
         * 方法引用形式中并没有明确给出Math.max函数的形参,但实际上由于方冒号: :左边给出了调用的函数所在类,右边给出了调用的函数名,所以编译器是知道形参个数类型和顺序的,无需给出参数列表,Math::max就是接口中唯一抽象函数getMax重写后的函数体,在调用useInterA(InterA interA, int num1, int num2)的时候实参num1 num2按照顺序赋值给了interA.getMax(num1, num2)中的num1 num2,然后调用getMax函数体中的Math.max函数时依照参数列表的顺序赋值给了public static int max(int a, int b)中的形参,返回运算结果,不是所有函数都可以缩写成方法引用的,只有在重写函数的形参与内部调用的其他函数的实参顺序一致时才可以使         */


        //场景2:对象名::成员方法名
        useInterB(new InterB() {
            @Override
            public void print(String str) {
                System.out.println(str);
            }
        }, "kunkun");//原始匿名内部类形式

        useInterB(str -> System.out.println(str), "kunkun");//lambda表达式形式

        useInterB(System.out::println, "坤坤");//方法引用形式


        //场景3:类名::new
        userInterC(new InterC() {
            @Override
            public Student getStudent() {
                return new Student();
            }
        });////原始匿名内部类形式
        userInterC(() -> new Student());//lambda表达式形式
        userInterC(Student::new);//方法引用形式
    }

    //设计使用InterA接口方法
    //参数1:接口A实现类对象 参数2,参数3是getMax()执行需要的数据
    public static int useInterA(InterA interA, int num1, int num2) {
        return interA.getMax(num1, num2);//通过return 返回结果
    }

    //设计使用InterB接口方法
    public static void useInterB(InterB interB, String str) {
        interB.print(str);
    }

    //设计使用InterC接口方法
    public static Student userInterC(InterC interC) {
        return interC.getStudent();
    }
}

class Student {
}

